package com.xksms.miniotest.utils;


import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName ImageUtil
 * @Description 基于Thumbnailator的图片工具类
 * @Author 程超
 * @Date 2022/7/29 10:13
 */
@Component
public class ImageUtil {
    /***
     * 一行的总宽度（像素）
     **/
    private static int maxWidth = 1000;
    /***
     * 宽度超过3000的文件为大文件 采用fontMAX
     **/
    private static final int BIGFILE = 3000;
    /***
     * 宽度超过2000 小于3000的文件为大文件 fontMedium
     **/
    private static final int MEDFILE = 2000;

    /***
     * 宽度超过1000 小于2000的文件为大文件 fontSmall
     **/
    private static final int SMALLFILE = 1000;
    /**
     * 水印文字字体
     **/
    private static final Font FONTMAX = new Font("宋体", Font.BOLD, 80);
    private static final Font FONTBIG = new Font("宋体", Font.BOLD, 60);
    private static final Font FONTMEDIUM = new Font("宋体", Font.BOLD, 40);
    private static final Font FONTSMALL = new Font("宋体", Font.BOLD, 20);


    /**
     * @param inputStream      文件输入流
     * @param quality          压缩系数 1为百分之百
     * @param positions        位置
     * @param waterMarkContent 水印内容
     * @return java.io.InputStream
     * @Author chengchao
     * @Description 压缩并加水印
     * @Date 17:45 2022/8/1
     **/
    public static File compressPic(InputStream inputStream, float quality, String positions, String waterMarkContent, String rgb, float alpha) {
        File file = new File("test.jpg");
        try {
            BufferedImage image = selectSize(inputStream, waterMarkContent, rgb);
            Thumbnails.of(inputStream)
                    .scale(1f)
                    .watermark(Positions.valueOf(positions), image, alpha)
                    .outputQuality(quality)
                    .toFile(file);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return file;

    }

    public static File compressPic(MultipartFile file, float quality, String positions, String waterMarkContent, String rgb, float alpha) {
        File newFile = new File("test.jpg");
        try {
            BufferedImage image = selectSize(file.getInputStream(), waterMarkContent, rgb);
            Thumbnails.of(file.getInputStream())
                    .scale(1f)
                    .watermark(Positions.valueOf(positions), image, alpha)
                    .outputQuality(quality)
                    .toFile(newFile);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return newFile;

    }

    /**
     * @param inputStream      文件流
     * @param waterMarkContent 水印内容
     * @param rgb              颜色rgb值
     * @return java.awt.image.BufferedImage
     * @Author chengchao
     * @Description
     * @Date 17:27 2022/8/4
     **/
    public static BufferedImage selectSize(InputStream inputStream, String waterMarkContent, String rgb) throws Exception {
        BufferedImage bufferedImage = ImageIO.read(inputStream);
        int width = bufferedImage.getWidth();
        BufferedImage image;
        if (width > BIGFILE) {
            maxWidth = (int) ((width / 3)>FONTMAX.getSize()*17?(width / (0.6f)):FONTMAX.getSize()*17);
            image = getImage(waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTMAX);
        } else if (width > MEDFILE) {
            maxWidth = (int) ((width / 2)>FONTBIG.getSize()*17?(width / (0.6f)):FONTBIG.getSize()*17);
            image = getImage(waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTBIG);
        } else if (width>SMALLFILE) {
            maxWidth = (int) ((width / (1.5f))>FONTMEDIUM.getSize()*17?(width / (0.6f)):FONTMEDIUM.getSize()*17);
            image = getImage(waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTMEDIUM);
        } else {
            maxWidth = (int) ((width / (1.2f))>FONTSMALL.getSize()*17?(width / (0.6f)):FONTSMALL.getSize()*17);
            image = getImage(waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTSMALL);
        }
        return image;
    }

    /**
     * @param waterMarkContent 水印内容
     * @return java.awt.image.BufferedImage
     * @Author chengchao
     * @Description 创建新图片
     * @Date 17:47 2022/8/1
     **/
    public static BufferedImage getImage(String waterMarkContent, Color color, Font font) {
        Map<String, Integer> heightWith = getHeightWith(waterMarkContent, font);
        int height = heightWith.get("height");
        int width = heightWith.get("width");
        //获取到长度后绘制正确的图片
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) bi.getGraphics();
        g2.setBackground(Color.WHITE);
//        g2.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g2.clearRect(0, 0, width, height);
        return addWatermark(bi, waterMarkContent, color, font);
    }

    /**
     * @param waterMarkContent 水印内容
     * @param font             font
     * @return java.util.Map
     * @Author chengchao
     * @Description 计算画板尺寸
     * @Date 17:43 2022/8/3
     **/
    public static Map<String, Integer> getHeightWith(String waterMarkContent, Font font) {
        int fontSize = font.getSize();
        //这个image是个临时的 为了获取绘制的文字的长度
        BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        // 创建一个FontMetrics对象
        FontMetrics fm = g.getFontMetrics(font);
        //获取文字的长度 除以maxWidth 就是水印的行数
        int height = 0;
        String[] strings = waterMarkContent.split("\\\\");
        for (String string : strings) {
            int i = fm.stringWidth(string) / maxWidth + 1;
            height += i;
        }
        //乘以行高 就是实际的高度
        height = height * (fontSize + fontSize / 4);
        int width = Math.min(maxWidth, fm.stringWidth(waterMarkContent));
        Map<String, Integer> map = new HashMap<>(2);
        map.put("width", width);
        map.put("height", height);
        return map;
    }


    /**
     * @param sourceImgPath    源图片路径
     * @param waterMarkContent 水印内容
     * @return java.awt.image.BufferedImage
     * @Author chengchao
     * @Description 生成水印图片
     * @Date 17:48 2022/8/1
     **/
    public static BufferedImage addWatermark(BufferedImage sourceImgPath, String waterMarkContent, Color color, Font font) {
        int fontSize = font.getSize();
        // 设置水印文字的旋转角度
//        Integer degree = null;
        try {

            // 获取图片的宽
            int srcImgWidth = sourceImgPath.getWidth(null);
            // 获取图片的高
            int srcImgHeight = sourceImgPath.getHeight(null);
            // 加水印
            BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
            // 得到画笔
            Graphics2D g = bufImg.createGraphics();
            g.drawImage(sourceImgPath, 0, 0, srcImgWidth, srcImgHeight, null);
            // 设置水印颜色sssssssssssssssss
            g.setColor(color);
            // 设置字体
            //自动根据水印大小调节字体大小
            g.setFont(font);
            // 设置水印文字透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1f));
//            if (null != degree) {
//                // 设置水印旋转
//                g.rotate(Math.toRadians(degree));
//            }
            // 画出水印,并设置水印位置 x坐标即字符串左边位置，y坐标是指baseline的y坐标，即字体所在矩形的左上角y坐标+ascent
//            //graphics.drawString(DateUtil.formatDate(new java.util.Date(),DateUtil.FULL_TRADITION_PATTERN),10,10+metrics.getAscent()); //基线对齐改为顶边对齐
//            FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
//            int strWidth = metrics.stringWidth(waterMarkContent);
//            int strHeight = metrics.getHeight();
//            int owidth = bufImg.getWidth();
//            int oheight = bufImg.getHeight();
//            int left = (owidth-strWidth)/2; //左边位置
//            int top = (oheight-strHeight)/2+metrics.getAscent(); //顶边位置+上升距离（原本字体基线位置对准画布的y坐标导致字体偏上ascent距离，加上ascent后下移刚好顶边吻合）
//            g.drawString(waterMarkContent, left, top);
            JLabel jLabel = new JLabel(waterMarkContent);
            jLabel.setFont(font);
            FontMetrics fontMetrics = jLabel.getFontMetrics(font);
            int textLength = waterMarkContent.length();
            //一行的总长度，用于判断是否超出了范围
            int totalWidth = fontMetrics.stringWidth(waterMarkContent);
            //计算一行的高度
            int textHeight = fontMetrics.getHeight();
            // 总长度超过了整个长度限制
            if (totalWidth > maxWidth) {
                //已经写了多少行
                int alreadyWriteLine = 0;
                //目前一行写的长度
                int nowWidth = 0;
                for (int i = 0; i < textLength; i++) {
                    //获取单个字符的长度
                    int oneWordWidth = fontMetrics.charWidth(waterMarkContent.charAt(i));
                    //判断目前的一行加上这个字符的长度是否超出了总长度
                    int tempWidth = oneWordWidth + nowWidth;
                    if (tempWidth > maxWidth) {
                        // 如果超出了一行的总长度，则要换成下一行
                        nowWidth = 0;
                        alreadyWriteLine++;
                        int writeY = fontSize - 5 + alreadyWriteLine * (textHeight);
                        g.drawString(waterMarkContent.charAt(i) + "", nowWidth, writeY);
                        nowWidth = oneWordWidth;
                    } else {
                        if (waterMarkContent.charAt(i) == '\\') {
                            //如果是换行符，则不用写入，直接跳过
                            nowWidth = maxWidth + 1;
                            continue;
                        }
                        // 当前行长度足够，可以直接画
                        int writeY = fontSize - 5 + alreadyWriteLine * (textHeight);
                        g.drawString(waterMarkContent.charAt(i) + "", nowWidth, writeY);
                        nowWidth = tempWidth;
                    }
                }
            } else {
                //没有超过限制，直接画
                g.drawString(waterMarkContent, 0, fontSize - fontSize / 10);
            }
            // 释放资源
            g.dispose();
//             直接输出文件用来测试结果
        ImageIO.write(bufImg, "png", new File("test1.png"));
            return transferAlpha(bufImg);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * @param bufImg 源图片
     * @return java.awt.image.BufferedImage
     * @Author chengchao
     * @Description 转化成透明背景的图片
     * @Date 17:48 2022/8/1
     **/
    public static BufferedImage transferAlpha(BufferedImage bufImg) {

        try {
            ImageIcon imageIcon = new ImageIcon(bufImg);
            BufferedImage bufferedImage = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(),
                    BufferedImage.TYPE_4BYTE_ABGR);
            Graphics2D g2D = (Graphics2D) bufferedImage.getGraphics();
            g2D.drawImage(imageIcon.getImage(), 0, 0, imageIcon.getImageObserver());
            int alpha = 0;
            for (int j1 = bufferedImage.getMinY(); j1 < bufferedImage.getHeight(); j1++) {
                for (int j2 = bufferedImage.getMinX(); j2 < bufferedImage.getWidth(); j2++) {
                    int rgb = bufferedImage.getRGB(j2, j1);
                    int r = (rgb & 0xff0000) >> 16;
                    int g = (rgb & 0xff00) >> 8;
                    int b = (rgb & 0xff);
                    if (((255 - r) < 30) && ((255 - g) < 30) && ((255 - b) < 30)) {
                        rgb = ((alpha + 1) << 24) | (rgb & 0x00ffffff);
                    }
                    bufferedImage.setRGB(j2, j1, rgb);
                }
            }
            g2D.drawImage(bufferedImage, 0, 0, imageIcon.getImageObserver());
            // 直接输出文件用来测试结果
            //ImageIO.write(bufferedImage, "png", new File("test2.png"));
            return bufferedImage;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

 /**
     * @param inputStream      文件流
     * @param waterMarkContent 水印内容
     * @param rgb              颜色rgb值
     * @return java.awt.image.BufferedImage
     * @Author chengchao
     * @Description
     * @Date 17:27 2022/8/4
     **/
    public static BufferedImage getTextWatermarkPic(InputStream inputStream, String waterMarkContent, String rgb) throws Exception {
        BufferedImage bufferedImage = ImageIO.read(inputStream);
        int width = bufferedImage.getWidth();
        BufferedImage image;
        if (width > BIGFILE) {
            maxWidth = ((width / 3)>FONTMAX.getSize()*17?(width / (3)):FONTMAX.getSize()*20);
            image = addTextWaterMark(bufferedImage,waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTMAX);
        } else if (width > MEDFILE) {
            maxWidth =((width / 2)>FONTBIG.getSize()*17?(width / (2)):FONTBIG.getSize()*20);
            image = addTextWaterMark(bufferedImage,waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTBIG);
        } else if (width>SMALLFILE) {
            maxWidth = (int) ((width / (1.5f))>FONTMEDIUM.getSize()*17?(width / (1.5f)):FONTMEDIUM.getSize()*20);
            image = addTextWaterMark(bufferedImage,waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTMEDIUM);
        } else {
            maxWidth = (int) ((width / (1.2f))>FONTSMALL.getSize()*17?(width / (1.2f)):FONTSMALL.getSize()*20);
            image = addTextWaterMark(bufferedImage,waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTSMALL);
        }
        return image;
    }

    /**
     * @description 添加文本水印， 这是图片水印方法用的
     * @param sourceImgPath 源img路径
     * @param waterMarkContent 水痕含量
     * @param color 颜色
     * @param font 字体
     * @return {@link BufferedImage }
     *
     * @author 程超
     * @date 2023/01/06 11:28:22
     */
    public static BufferedImage addTextWaterMark(BufferedImage sourceImgPath, String waterMarkContent, Color color,Font font) {
//        BufferedImage sourceImgPath = ImageIO.read(inputStream);
        int fontSize = font.getSize();
        // 设置水印文字的旋转角度
//        Integer degree = null;
        try {
            // 获取源图片的宽高
            int srcImgWidth = sourceImgPath.getWidth();
            int srcImgHeight = sourceImgPath.getHeight();
            //获得文字所需要的宽高
            Map<String, Integer> heightWith = getHeightWith(waterMarkContent, font);
            // 加水印
            BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
            // 得到画笔
            Graphics2D g = bufImg.createGraphics();
            int y = srcImgHeight - (heightWith.get("height") + 2 * fontSize);
            g.drawImage(sourceImgPath, 0, 0, srcImgWidth, srcImgHeight, null);
            // 设置水印颜色
            g.setColor(color);
            // 设置字体
            //自动根据水印大小调节字体大小
            g.setFont(font);
            // 设置水印文字透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1f));
//            if (null != degree) {
//                // 设置水印旋转
//                g.rotate(Math.toRadians(degree));
//            }
            // 画出水印,并设置水印位置 x坐标即字符串左边位置，y坐标是指baseline的y坐标，即字体所在矩形的左上角y坐标+ascent
            JLabel jLabel = new JLabel(waterMarkContent);
            jLabel.setFont(font);
            FontMetrics fontMetrics = jLabel.getFontMetrics(font);
            int textLength = waterMarkContent.length();
            //一行的总长度，用于判断是否超出了范围
            int totalWidth = fontMetrics.stringWidth(waterMarkContent);
            //计算一行的高度
            int textHeight = fontMetrics.getHeight();
            // 总长度超过了整个长度限制
            if (totalWidth > maxWidth) {
                //已经写了多少行
                int alreadyWriteLine = 0;
                //目前一行写的长度
                int nowWidth = 0;
                for (int i = 0; i < textLength; i++) {
                    //获取单个字符的长度
                    int oneWordWidth = fontMetrics.charWidth(waterMarkContent.charAt(i));
                    //判断目前的一行加上这个字符的长度是否超出了总长度
                    int tempWidth = oneWordWidth + nowWidth;
                    if (tempWidth > maxWidth) {
                        // 如果超出了一行的总长度，则要换成下一行
                        nowWidth = 0;
                        alreadyWriteLine++;
                        int writeY =y+ fontSize - 5 + alreadyWriteLine * (textHeight);
                        g.drawString(waterMarkContent.charAt(i) + "", nowWidth, writeY);
                        nowWidth = oneWordWidth;
                    } else {
                        if (waterMarkContent.charAt(i) == '\\') {
                            //如果是换行符，则不用写入，直接跳过
                            nowWidth = maxWidth + 1;
                            continue;
                        }
                        // 当前行长度足够，可以直接画
                        int writeY = y+fontSize - 5 + alreadyWriteLine * (textHeight);
                        g.drawString(waterMarkContent.charAt(i) + "", nowWidth, writeY);
                        nowWidth = tempWidth;
                    }
                }
            } else {
                //没有超过限制，直接画
                g.drawString(waterMarkContent, 0, y+fontSize - fontSize / 10);
            }
            // 释放资源
            g.dispose();
//             直接输出文件用来测试结果
            ImageIO.write(bufImg, "png", new File("test1.png")) ;
            return bufImg;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    /**
     * @param url      minio中文件的url
     * @param waterMarkContent 水印内容
     * @return java.awt.image.BufferedImage
     * @Author chengchao
     * @Description 直接获得文字水印
     * @Date 17:27 2022/8/4
     **/
    public static File getTextWatermarkPic(String url, String waterMarkContent) throws Exception {
        String rgb="ffffff";
        InputStream inputStream = MinioUtil.download(url);
        BufferedImage bufferedImage = ImageIO.read(inputStream);
        int width = bufferedImage.getWidth();
        File image;
        if (width > BIGFILE) {
            maxWidth = ((width / 3)<FONTMAX.getSize()*17?(width / (3)):FONTMAX.getSize()*20);
            image = addTextWaterMarking(bufferedImage,waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTMAX);
        } else if (width > MEDFILE) {
            maxWidth =((width / 2)<FONTBIG.getSize()*17?(width / (2)):FONTBIG.getSize()*20);
            image = addTextWaterMarking(bufferedImage,waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTBIG);
        } else if (width>SMALLFILE) {
            maxWidth = (int) ((width / (1.5f))<FONTMEDIUM.getSize()*20?(width / (1.5f)):FONTMEDIUM.getSize()*20);
            image = addTextWaterMarking(bufferedImage,waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTMEDIUM);
        } else {
            maxWidth = (int) ((width / (1.2f))<FONTSMALL.getSize()*20?(width / (1.2f)):FONTSMALL.getSize()*20);
            image = addTextWaterMarking(bufferedImage,waterMarkContent, new Color(Integer.parseInt(rgb, 16)), FONTSMALL);
        }
        inputStream.close();
        return image;
    }


    /**
     * description:  文字水印
     * @param sourceImgPath 源图片
     * @param waterMarkContent 水印内容
     * @param color 颜色
     * @param font  字体
     * @return java.awt.image.BufferedImage
     * @author ChengChao
     * @date  2022/8/26 14:34
     */
    public static File addTextWaterMarking(BufferedImage sourceImgPath, String waterMarkContent, Color color,Font font)  {
        int fontSize = font.getSize();
        // 设置水印文字的旋转角度
//        Integer degree = null;
        try {
            // 获取源图片的宽高
            int srcImgWidth = sourceImgPath.getWidth();
            int srcImgHeight = sourceImgPath.getHeight();
            //获得文字所需要的宽高
            Map<String, Integer> heightWith = getHeightWith(waterMarkContent, font);
            // 加水印
            BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
            // 得到画笔
            Graphics2D g = bufImg.createGraphics();
            int y = srcImgHeight - (heightWith.get("height") + 2 * fontSize);
            g.drawImage(sourceImgPath, 0, 0, srcImgWidth, srcImgHeight, null);
            // 设置水印颜色
            g.setColor(color);
            // 设置字体
            //自动根据水印大小调节字体大小
            g.setFont(font);
            // 设置水印文字透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1f));
//            if (null != degree) {
//                // 设置水印旋转
//                g.rotate(Math.toRadians(degree));
//            }
            // 画出水印,并设置水印位置 x坐标即字符串左边位置，y坐标是指baseline的y坐标，即字体所在矩形的左上角y坐标+ascent
            JLabel jLabel = new JLabel(waterMarkContent);
            jLabel.setFont(font);
            FontMetrics fontMetrics = jLabel.getFontMetrics(font);
            int textLength = waterMarkContent.length();
            //一行的总长度，用于判断是否超出了范围
            int totalWidth = fontMetrics.stringWidth(waterMarkContent);
            //计算一行的高度
            int textHeight = fontMetrics.getHeight();
            // 总长度超过了整个长度限制
            if (totalWidth > maxWidth) {
                //已经写了多少行
                int alreadyWriteLine = 0;
                //目前一行写的长度
                int nowWidth = 0;
                for (int i = 0; i < textLength; i++) {
                    //获取单个字符的长度
                    int oneWordWidth = fontMetrics.charWidth(waterMarkContent.charAt(i));
                    //判断目前的一行加上这个字符的长度是否超出了总长度
                    int tempWidth = oneWordWidth + nowWidth;
                    if (tempWidth > maxWidth) {
                        // 如果超出了一行的总长度，则要换成下一行
                        if (waterMarkContent.charAt(i) == '\\'){
                            continue;
                        }
                        nowWidth = 0;
                        alreadyWriteLine++;
                        int writeY =y+ fontSize - 5 + alreadyWriteLine * (textHeight);
                        g.drawString(waterMarkContent.charAt(i) + "", nowWidth, writeY);
                        nowWidth = oneWordWidth;
                    } else {
                        if (waterMarkContent.charAt(i) == '\\') {
                            //如果是换行符，则不用写入，直接跳过
                            nowWidth = maxWidth + 1;
                            continue;
                        }
                        // 当前行长度足够，可以直接画
                        int writeY = y+fontSize - 5 + alreadyWriteLine * (textHeight);
                        g.drawString(waterMarkContent.charAt(i) + "", nowWidth, writeY);
                        nowWidth = tempWidth;
                    }
                }
            } else {
                //没有超过限制，直接画
                g.drawString(waterMarkContent, 0, y+fontSize - fontSize / 10);
            }
            // 释放资源
            g.dispose();
//             直接输出文件用来测试结果
            //random生成随机数

            File file = new File( 1+ ".jpg");
            ImageIO.write(bufImg, "jpg", file) ;
            return file;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
